package com.studyweb.service.impl;

import com.studyweb.mapper.UserCheckinMapper;
import com.studyweb.pojo.entity.UserAchievement;
import com.studyweb.pojo.entity.UserCheckin;
import com.studyweb.service.UserAchievementService;
import com.studyweb.service.UserCheckinService;
import com.studyweb.service.UserPointsService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.YearMonth;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 用户签到服务实现类
 * 
 * @author StudyWeb Team
 * @since 1.0.0
 */
@Slf4j
@Service
public class UserCheckinServiceImpl implements UserCheckinService {

    @Autowired
    private UserCheckinMapper userCheckinMapper;
    
    @Autowired
    private UserPointsService userPointsService;
    
    @Autowired
    private UserAchievementService userAchievementService;

    /**
     * 用户签到
     *
     * @param userId 用户ID
     * @return 签到结果，包含连续签到天数和获得的积分
     */
    @Override
    @Transactional
    public UserCheckin checkin(Long userId) {
        LocalDate today = LocalDate.now();
        
        // 检查今天是否已经签到
        UserCheckin todayCheckin = userCheckinMapper.selectByUserIdAndDate(userId, today);
        if (todayCheckin != null) {
            log.info("用户今日已签到: {}", userId);
            return todayCheckin;
        }
        
        // 获取最近一次签到记录
        UserCheckin latestCheckin = userCheckinMapper.selectLatestByUserId(userId);
        
        // 计算连续签到天数
        int consecutiveDays = 1; // 默认为1（今天）
        if (latestCheckin != null) {
            LocalDate lastCheckinDate = latestCheckin.getCheckinDate();
            long daysBetween = ChronoUnit.DAYS.between(lastCheckinDate, today);
            
            // 如果是昨天签到的，连续天数+1
            if (daysBetween == 1) {
                consecutiveDays = latestCheckin.getStreakCount() + 1;
            } else if (daysBetween > 1) {
                // 中断了连续签到
                consecutiveDays = 1;
            }
        }
        
        // 计算累计签到次数（包括当前这次签到）
        int totalCheckins = userCheckinMapper.countByUserId(userId) + 1;
        
        // 计算获得的积分
        int pointsEarned = calculatePoints(consecutiveDays, totalCheckins);
        
        // 创建新的签到记录
        UserCheckin newCheckin = new UserCheckin();
        newCheckin.setUserId(userId);
        newCheckin.setCheckinDate(today);
        newCheckin.setCheckinTime(LocalDateTime.now());
        newCheckin.setStreakCount(consecutiveDays);
        newCheckin.setPointsEarned(pointsEarned);
        
        // 保存签到记录
        userCheckinMapper.insert(newCheckin);
        log.info("用户签到成功: {}, 连续签到天数: {}, 获得积分: {}", userId, consecutiveDays, pointsEarned);
        
        // 增加用户积分
        userPointsService.addPoints(userId, pointsEarned);
        
        // 检查并授予签到相关成就
        List<UserAchievement> newAchievements = userAchievementService.checkAndGrantCheckinAchievements(userId, consecutiveDays, totalCheckins);
        
        // 如果获得了新成就，记录日志
        if (!newAchievements.isEmpty()) {
            for (UserAchievement achievement : newAchievements) {
                log.info("用户获得新成就: {}, 成就名称: {}", userId, achievement.getAchievement().getName());
            }
        }
        
        return newCheckin;
    }

    /**
     * 获取用户今日签到状态
     *
     * @param userId 用户ID
     * @return 今日是否已签到
     */
    @Override
    public boolean isCheckedInToday(Long userId) {
        LocalDate today = LocalDate.now();
        UserCheckin todayCheckin = userCheckinMapper.selectByUserIdAndDate(userId, today);
        return todayCheckin != null;
    }

    /**
     * 获取用户连续签到天数
     *
     * @param userId 用户ID
     * @return 连续签到天数
     */
    @Override
    public int getConsecutiveDays(Long userId) {
        Integer days = userCheckinMapper.getConsecutiveDays(userId);
        return days != null ? days : 0;
    }

    /**
     * 获取用户指定日期的签到记录
     *
     * @param userId 用户ID
     * @param date 日期
     * @return 签到记录，如果不存在则返回null
     */
    @Override
    public UserCheckin getCheckinByDate(Long userId, LocalDate date) {
        return userCheckinMapper.selectByUserIdAndDate(userId, date);
    }
    
    /**
     * 获取用户指定日期范围内的签到记录
     *
     * @param userId 用户ID
     * @param startDate 开始日期
     * @param endDate 结束日期
     * @return 签到记录列表
     */
    @Override
    public List<UserCheckin> getCheckinRecordsByDateRange(Long userId, LocalDate startDate, LocalDate endDate) {
        return userCheckinMapper.selectByUserIdAndDateRange(userId, startDate, endDate);
    }
    
    /**
     * 根据连续签到天数计算获得的积分
     *
     * @param consecutiveDays 连续签到天数
     * @param totalCheckins 累计签到天数（包括当前签到）
     * @return 获得的积分
     */
    private int calculatePoints(int consecutiveDays, int totalCheckins) {
        // 基础积分：每次签到获得5积分
        int basePoints = 5;
        
        // 连续签到奖励
        int consecutiveBonus = 0;
        if (consecutiveDays >= 3 && consecutiveDays < 7) {
            consecutiveBonus = 5;  // 连续3天奖励5分
        } else if (consecutiveDays >= 7 && consecutiveDays < 15) {
            consecutiveBonus = 10; // 连续7天奖励10分
        } else if (consecutiveDays >= 15 && consecutiveDays < 30) {
            consecutiveBonus = 20; // 连续15天奖励20分
        } else if (consecutiveDays >= 30) {
            consecutiveBonus = 50; // 连续30天奖励50分
        }
        
        // 累计签到奖励
        int accumulatedBonus = 0;
        if (totalCheckins >= 10 && totalCheckins < 30) {
            accumulatedBonus = 10;  // 累计10天奖励10分
        } else if (totalCheckins >= 30 && totalCheckins < 100) {
            accumulatedBonus = 30;  // 累计30天奖励30分
        } else if (totalCheckins >= 100) {
            accumulatedBonus = 100; // 累计100天奖励100分
        }
        
        return basePoints + consecutiveBonus + accumulatedBonus;
    }
}